package com.lambo.maven.core.utils;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class IOUtil {
    private final static Logger logger = LoggerFactory.getLogger(IOUtil.class);
    /**
     * 文件协议.
     */
    public static final String PROTOCOL_FILE = "file";
    /**
     * 支持classpath.
     */
    public static final String CLASSPATH_STR = "classpath:";
    /**
     * 路径分割符.
     */
    public static final String PREFIX_SLASH = "/";

    /**
     * 支持http协议.
     */
    public static final String PROTOCOL_HTTP = "http";

    /**
     * IO操作中共同的关闭方法
     *
     * @param closeable 可关闭工具.
     * @createTime 2014年12月14日 下午7:50:56
     */
    public static void closeIo(AutoCloseable closeable) {
        if (null != closeable) {
            try {
                closeable.close();
            } catch (Exception ignored) {
            }
        }
    }

    /**
     * 强制读取多少字节.
     * @param inStream
     * @param length
     * @return
     * @throws IOException
     */
    public static byte[] readToByteBufferByLength(InputStream inStream, int length) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        if (length > 0) {
            int bufferSize = 0x2000;
            byte[] buffer = new byte[bufferSize];
            int read;
            int remaining = length;

            while (remaining > 0) {
                if (remaining < bufferSize) {
                    buffer = new byte[remaining];
                }
                read = inStream.read(buffer);
                if (-1 == read) {
                    break;
                }
                remaining -= read;
                outStream.write(buffer, 0, read);
            }
        }
        return outStream.size() > 0 ? outStream.toByteArray() : null;
    }

    /**
     * 读取文件.
     * @param fileName 文件名称.
     * @return 字节数组.
     * @throws IOException 异常.
     */
    public static byte[] readToByteBuffer(String fileName) throws IOException {
        URL url = getFileEveryWhere(fileName);
        if (null == url) {
            throw new FileNotFoundException(fileName);
        }
        if (PROTOCOL_FILE.equalsIgnoreCase(url.getProtocol())) {
            try {
                return readToByteBuffer(new File(url.toURI()));
            } catch (URISyntaxException e) {
                throw new IOException(e);
            }
        }
        try (InputStream inStream = url.openStream()) {
            return readToByteBuffer(inStream);
        }
    }

    /**
     * 读取文件.
     * @param file 文件.
     * @return 数据.
     * @throws IOException 异常.
     */
    public static byte[] readToByteBuffer(File file) throws IOException {
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在");
        }
        BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(file));
        try {
            return readToByteBuffer(inStream, (int) file.length());
        } finally {
            IOUtil.closeIo(inStream);
        }
    }

    /**
     * 读取数据.最多多少数据,
     * @param inStream 流.
     * @param maxSize 大小.
     * @return
     * @throws IOException
     */
    public static byte[] readToByteBuffer(InputStream inStream, int maxSize) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        if (maxSize > 0) {
            int bufferSize = 0x2000;
            if (bufferSize > maxSize) {
                bufferSize = maxSize;
            }
            byte[] buffer = new byte[bufferSize];
            int read;
            int remaining = maxSize;

            while (true) {
                read = inStream.read(buffer);
                if (-1 == read) {
                    break;
                }
                if (read > remaining) {
                    outStream.write(buffer, 0, read);
                    break;
                }
                remaining -= read;
                outStream.write(buffer, 0, read);
                if (remaining <= 0) {
                    break;
                }
                if (bufferSize > read && inStream.available() == 0) {
                    break;
                }
            }
        }
        return outStream.size() > 0 ? outStream.toByteArray() : null;
    }

    /**
     * 读取最多10M数据.
     * @param inStream 数据流,
     * @return 数据.
     * @throws IOException 异常.
     */
    public static byte[] readToByteBuffer(InputStream inStream) throws IOException {
        return readToByteBuffer(inStream, 1024 * 1024 * 10);
    }

    /**
     * 查询文件.
     * @param path 地址.
     * @return url地址.
     */
    public static URL getFileEveryWhere(String path) {
        if (path.startsWith(CLASSPATH_STR)) {
            path = path.substring(CLASSPATH_STR.length());
            if (path.startsWith(PREFIX_SLASH)) {
                path = path.substring(1);
            }
            URL rs = Thread.currentThread().getContextClassLoader().getResource(path);
            if (null != rs) {
                return rs;
            }
            return null;
        }
        if (path.startsWith(PROTOCOL_HTTP)) {
            try {
                return new URL(path);
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        }
        File f = new File(path);
        try {
            if (f.exists()) {
                return f.toURI().toURL();
            }
            f = new File(System.getProperty("user.dir") + PREFIX_SLASH + path);
            if (f.exists()) {
                return f.toURI().toURL();
            }
        } catch (MalformedURLException ignored) {
        }
        return null;
    }

    /**
     * 写入文件.
     * @param filePath 文件地址.
     * @param data 数据.
     */
    public static void writeFile(String filePath, byte[] data) {
        if (null == filePath || filePath.trim().isEmpty() || null == data) {
            return;
        }
        File file = new File(filePath);
        if (null == file.getParent()) {
            file = new File(file.getAbsolutePath());
        }
        if (!file.getParentFile().exists()) {
            boolean success = file.getParentFile().mkdirs();
            if (!success) {
                throw new BizException(500, "mkdirs failed, path = " + file.getParentFile().getAbsolutePath());
            }
        }
        try (OutputStream out = new FileOutputStream(file)) {
            out.write(data);
            out.flush();
        } catch (Exception e) {
            logger.error("writeFile failed, path = {}, msg = {}", filePath, e.getLocalizedMessage(), e);
        }
    }
}
